﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FirstFloor.Documents.Pdf.ColorSpaces
{
    /// <summary>
    /// Represents the CalRGB color space.
    /// </summary>
    internal class CalRGB
        : ColorSpace
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CalRGB"/> class.
        /// </summary>
        public CalRGB()
        {
            this.Name = "CalRGB";
            this.DefaultColor = new double[] { 0, 0, 0 };

            this.WhitePoint = new ColorPoint() { X = 1, Y = 1, Z = 1 };
            this.BlackPoint = new ColorPoint() { X = 0, Y = 0, Z = 0 };
            this.Gamma = new ColorPoint() { X = 1, Y = 1, Z = 1 };
            this.Matrix = new double[9] { 1, 0, 0,
                                          0, 1, 0,
                                          0, 0, 1 };
            this.InverseMatrix = new double[9] { 1, 0, 0,
                                                 0, 1, 0,
                                                 0, 0, 1 };
        }

        /// <summary>
        /// Specifies the tristimulus value of the diffuse white point.
        /// </summary>
        /// <value>The white point.</value>
        public ColorPoint WhitePoint { get; set; }
        /// <summary>
        /// Specifies the tristimulus value of the diffuse black point.
        /// </summary>
        /// <value>The black point.</value>
        public ColorPoint BlackPoint { get; set; }
        /// <summary>
        /// Specifies the gamma for the red, green, and blue components of the color space.
        /// </summary>
        /// <value>The gamma.</value>
        public ColorPoint Gamma { get; set; }
        /// <summary>
        /// Specifies the linear interpretation of the decoded A, B, and C components of the color space with respect to the final XYZ representation.
        /// </summary>
        /// <value>The matrix.</value>
        public double[] Matrix { get; set; }
        /// <summary>
        /// Gets or sets the inverse matrix.
        /// </summary>
        /// <value>The inverse matrix.</value>
        public double[] InverseMatrix { get; set; }
        /// <summary>
        /// Converts specified value to the XYZ color space.
        /// </summary>
        /// <param name="values">The values.</param>
        /// <returns></returns>
        public override ColorPoint ToXYZ(params double[] values)
        {
            double a = Math.Pow(values[0], this.Gamma.X) * this.WhitePoint.X;
            double b = Math.Pow(values[1], this.Gamma.Y) * this.WhitePoint.Y;
            double c = Math.Pow(values[2], this.Gamma.Z) * this.WhitePoint.Z;

            return new ColorPoint() {
                X = a * this.Matrix[0] + b * this.Matrix[1] + c * this.Matrix[2],
                Y = a * this.Matrix[3] + b * this.Matrix[4] + c * this.Matrix[5],
                Z = a * this.Matrix[6] + b * this.Matrix[7] + c * this.Matrix[8],
            };
        }

        /// <summary>
        /// Converts a value from the XYZ color space to a value in this color space.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public override double[] FromXYZ(ColorPoint value)
        {
            double a = value.X * this.InverseMatrix[0] + value.Y * this.InverseMatrix[1] + value.Z * this.InverseMatrix[2];
            double b = value.X * this.InverseMatrix[3] + value.Y * this.InverseMatrix[4] + value.Z * this.InverseMatrix[5];
            double c = value.X * this.InverseMatrix[6] + value.Y * this.InverseMatrix[7] + value.Z * this.InverseMatrix[8];

            return new double[]{
                Math.Pow(a, 1D / this.Gamma.X) / this.WhitePoint.X,
                Math.Pow(b, 1D / this.Gamma.Y) / this.WhitePoint.Y,
                Math.Pow(c, 1D / this.Gamma.Z) / this.WhitePoint.Z
            };
        }
    }
}
